
// Copyright (c) WanSheng Intelligent Corp. All rights reserved.
// Licensed under the LGPL v3.0 license. 

#include <stdlib.h>
#include <pthread.h>

#include "modbus_module.h"
#include "modbus_plugin.h"
#include "wa_plugin_sdk.h"
#include "logs.h"

typedef struct 
{
    BROKER_HANDLE       broker;
    RESTFUL_CONTEXT     restful_context;
    void  *             task_scheduler;
    bool                started;
}MB_PLUGIN_HANDLE_DATA;

MB_PLUGIN_HANDLE_DATA * g_modbus_plugin_data = NULL;

RESTFUL_CONTEXT modbus_get_restful_context()
{
    return g_modbus_plugin_data?g_modbus_plugin_data->restful_context:NULL;
}

static void* MB_Plugin_ParseConfigurationFromJson(const char* configuration)
{
    (void)configuration;
    return NULL;
}

static void MB_Plugin_FreeConfiguration(void* configuration)
{
    (void)configuration;
}

static MODULE_HANDLE MB_Plugin_Create(BROKER_HANDLE broker, const void* configuration)
{
    MB_PLUGIN_HANDLE_DATA* result;
    WALOG("Enter %s: broker=[%p]", __FUNCTION__, broker);
    if ((broker == NULL))
    {
        ERROR("invalid arg broker=%p", broker);
        return NULL;
    }

    result = malloc_z(sizeof(MB_PLUGIN_HANDLE_DATA));
    if(result == NULL)
    {
        ERROR("unable to malloc");
        return NULL;
    }

    init_plugin();
    result->broker = broker;
    g_modbus_plugin_data = result;
    return result;
}

static void MB_Plugin_Destroy(MODULE_HANDLE module)
{
    WARNING2("Enter..");
    MB_PLUGIN_HANDLE_DATA* handleData = module;
    if(handleData->task_scheduler)
        bh_task_destroy_scheduler(handleData->task_scheduler);
    free(handleData);
    uninit_plugin();
    WARNING2("Exit..");
}

static void MB_Plugin_Receive(MODULE_HANDLE moduleHandle, MESSAGE_HANDLE messageHandle)
{
    static bool name = false;
    if(!name){
        prctl (PR_SET_NAME, "modbus_plugin");
        name = true;
    }
}

static void MB_Plugin_Start(MODULE_HANDLE module)
{
    MB_PLUGIN_HANDLE_DATA* handleData = module;

    // initiate the restful context
    RESTFUL_CONTEXT rest_context = WA_InitRestful(handleData->broker, module);
    handleData->restful_context = rest_context;

    // register the resource /mb2 for handling the incomming requests
    WA_RegisterResource(rest_context, "/mb2", plugin_res_mb, T_Default);

    // start a new thread for handling the tasks
    handleData->task_scheduler = bh_task_run_new_scheduler();

    // load the configured devices and setup the internal data structure
    const char * plugin_name = WA_GetModuleName(handleData->broker, module);
    load_plugin_device_cfg(plugin_name);

    // create a regular executed task for reconnecting the devices or buses
    wa_task_t task1 =  bh_new_task((char*)ZS_TASK_CONNECT,
        NULL, 
        true,
        1*1000,   // repeating task in 1000 ms
        task_bus_connect);
    bh_schedule_task(handleData->task_scheduler, task1, 0);

    // tell the framework this plugin can be unplugged on the fly
    WA_SetPlugin_Unplugable(handleData->broker, module, true);

    handleData->started = true;

}

static const MODULE_API_1 Modbus_APIS_all =
{
        {MODULE_API_VERSION_1},
        MB_Plugin_ParseConfigurationFromJson,
        MB_Plugin_FreeConfiguration,
        MB_Plugin_Create,
        MB_Plugin_Destroy,
        MB_Plugin_Receive,
        MB_Plugin_Start
};

MODULE_EXPORT const MODULE_API* Module_GetApi(MODULE_API_VERSION gateway_api_version)
{
    const MODULE_API * api;

    // check the SDK version compatibility.
    // Note: the library version in target may be different from the SDK version that this plugin was compiled with.
    if(WA_SDK_INTERFACE_VERSION_CURRENT < wa_sdk_get_interface_version_back())
    {
        printf("HelloWorld: WA_SDK_INTERFACE_VERSION_CURRENT (%d) < framework supported (%d)\n",
            WA_SDK_INTERFACE_VERSION_CURRENT, wa_sdk_get_interface_version_back());
        return NULL;
    }

    if (gateway_api_version >= Modbus_APIS_all.base.version)
    {
        api= (const MODULE_API*)&Modbus_APIS_all;
    }
    else
    {
        api = NULL;
    }

    return api;
}

